package com.tangsm.spring.boot.validation.controller;

import com.tangsm.spring.boot.validation.domain.entity.Student;
import com.tangsm.spring.boot.validation.domain.entity.User;
import com.tangsm.spring.boot.validation.domain.vo.Result;
import com.tangsm.spring.boot.validation.service.UserService;
import com.tangsm.spring.boot.validation.util.ValidatorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Optional;

/**
 * spring-boot-starter-validation 验证实例Demo
 *
 * @author tangsm
 */
@RestController
@RequestMapping("/v1/valid")
@Validated
public class ValidDemoController {
    private static final Logger log = LoggerFactory.getLogger(ValidDemoController.class);

    @Autowired
    private UserService userService;

    /**
     * 拦截器忽略白名单实例
     *
     * @return 响应信息
     */
    @GetMapping("/white")
    public Result<User> white() {
        return Result.success(userService.get(1));
    }

    /**
     * BindingResult通用接口验证
     * <p>BindingResult校验参数示例</p>
     * <p>@Validated与@Valid都能验证</p>
     *
     * @param user          参数实体
     * @param bindingResult 参数验证信息
     * @return 响应信息
     */
    @PostMapping
    public Result<User> add(@RequestBody @Valid User user, BindingResult bindingResult) {
        // 如果有参数校验失败，会将错误信息封装成对象组装在BindingResult里
        StringBuilder errors = new StringBuilder();
        for (ObjectError error : bindingResult.getAllErrors()) {
            errors.append(String.format("%s%n", error.getDefaultMessage()));
        }
        if (errors.length() > 0) {
            return Result.verifyError(errors.toString());
        }

        // 添加用户
        if (userService.add(user)) {
            return Result.success();
        }

        return Result.failure();
    }

    /**
     * 单个参数校验
     * <p>单个参数校验，方法所在的controller类上加入@Validated注解</p>
     * @return 响应信息
     */
    @GetMapping("/single")
    public Result<User> single(@NotNull(message = "ID不能为空") Integer id,
                               @NotBlank(message = "名称不能为空") String name,
                               @Max(value = 100, message = "年龄不能超过100") Integer age) {
        log.info("ID={}, name={}, age={}", id, name, age);
        return Result.success(userService.get(id));
    }

    /**
     * 根据ID查询
     *
     * @return 响应信息
     */
    @GetMapping("/formEntity")
    public Result<User> formEntity(@Valid User user) {
        return Result.success(userService.get(user.getId().intValue()));
    }

    /**
     * 验证带集合的实体对象
     *
     * @return 响应信息
     */
    @PostMapping("/validCollection")
    public Result<Student> validCollection(@RequestBody @Validated Student student) {
        log.info(student.toString());
        return Result.success(student);
    }

    /**
     * AOP切面实现校验参数实例
     *
     * @param user          参数实体
     * @param bindingResult 参数验证信息
     * @return 响应信息
     */
    @PostMapping("/aop")
    public Result<User> aop(@RequestBody @Valid User user, BindingResult bindingResult) {
        // 添加用户
        if (userService.add(user)) {
            return Result.success();
        }

        return Result.failure();
    }

    /**
     * ValidatorUtils工具类校验参数实例
     *
     * @param user 参数实体
     * @return 响应信息
     */
    @PostMapping("/util")
    public Result<User> util(User user) {
        Optional<String> s = ValidatorUtils.validate(user);
        if (s.isPresent()) {
            return Result.verifyError(s.get());
        }

        // 添加用户
        if (userService.add(user)) {
            return Result.success();
        }

        return Result.failure();
    }
}
